// James Fancy, May 2009
// http://happy.jamesfancy.cn

function AlDialog(selector, options, initFunc) {
    // default options
    this.$options = {
        mark: {
            background: "#666666",
            alpha: 40,
            clickToClose: true,
            zIndex: 100
        },
        dialog: {
            modal: true,
            zIndex: 120
        }
    };

    // $dialog and $mark should be jquery object
    this.$dialog = null;
    this.$mark = null;

    this.$initalize = initFunc;
    this.$closing;
    this.$closed;

    this.domsWithRef = new Array();

    // shortcut for jquery selector
    this.$ = function(selector) {
        return this.$dialog.find(selector);
    }

    // get the dialog jquery object
    this.jquery = function() {
        return this.$dialog;
    }

    this.$init = function(selector, options) {
        if (typeof(selector) == "string") {
            this.$dialog = $(selector);
        } else if (typeof(selector) == "object") {
            this.$dialog = selector;
        }

        if (this.$dialog == null) {
            return;
        }

        if (!this.$dialog.parent().is("body")) {
            this.$dialog.hide().remove().appendTo("body");
        }

        this.setOptions(options);

        if (typeof(this.$initalize) == "function") {
            this.$initalize();
        }
    }

    // set options
    this.setOptions = function(options) {
        if (typeof(options) != "object" || options == null) {
            return;
        }

        if (typeof(options.mark) == "object" && options.mark != null) {
            for (var key in this.$options.mark) {
                if (typeof(options.mark[key]) != "undefined") {
                    this.$options.mark[key] = options.mark[key];
                }
            }
        }
        if (typeof(options.dialog) == "object" && options.dialog != null) {
            for (var key in this.$options.dialog) {
                if (typeof(options.dialog[key]) != "undefined") {
                    this.$options.dialog[key] = options.dialog[key];
                }
            }
        }
    }

    // bind closing event of the dialog.
    // if the callback function return false, the dialog should not be closed.
    this.closing = function(func) {
        this.$closing = func;
        return this;
    }

    // bind closed event of the dialog
    // normally get result in this callback function
    this.closed = function(func) {
        this.$closed = func;
        return this;
    }

    // bind a events to controls in pass-in json object
    this.bind = function(jsonObj) {
        if (typeof(jsonObj) != "object" || jsonObj == null) {
            return this;
        }
        for (var selector in jsonObj) {
            this.bindEvents(selector, jsonObj[selector]);
        }
        return this;
    }

    // bind events to the specified control.
    this.bindEvents = function(selector, events) {
        if (typeof(selector).match(/string|object/) == null || selector == null) {
            return this;
        }
        for (var type in events) {
            this.bindEvent(selector, type, events[type]);
        }
        return this;
    }

    // bind specified event to specified control
    this.bindEvent = function(selector, type, func) {
        if (typeof(type) != "string") {
            return this;
        }
        var control;
        if (typeof(selector) == "string") {
            control = this.$(selector);
        } else if (typeof(selector == "object")) {
            control = selector;
        }

        controls = control.get();
        for (var i = 0; i < controls.length; i++) {
            controls[i].alDialog = this;
            this.domsWithRef.push(controls[i]);
        }

        // JQuery hover evnet need two callback function
        // so specified as a array
        if (type == "hover") {
            if (typeof(func) == "function") {
                control.hover(func);
            } else if (typeof(func) == "object" && func instanceof Array) {
                control.hover(
                    (func.length > 0 && typeof(func[0]) == "function") ? func[0] : undefined,
                    (func.length > 1 && typeof(func[1]) == "function") ? func[1] : undefined
                );
            }

            return this;
        }

        eval("control." + type + "(func)");
        return this;
    }

    this.result = function(result) {
        if (result == undefined) {
            return this.$result;
        } else {
            this.$result = result;
            return this;
        }
    }

    this.show = function() {
        if (this.$options.dialog.modal) {
            this.showModal();
        } else {
            this.$show();
        }
        return this;
    }

    this.showModal = function() {
        this.$showMark();
        this.$show();
        return this;
    }

    this.$show = function() {
        var dialog = this.$dialog

        dialog.hide();
        if (!dialog.parent().is("body")) {
            dialog.remove.appendTo("body");
        }
        dialog.css({
            "z-index": this.$options.dialog.zIndex,
            "position": "absolute",
            "left": "50%",
            "margin-left": "-" + parseInt(dialog.width() / 2) + "px",
            "top": "50%",
            "margin-top": "-" + parseInt(dialog.height() / 2) + "px"
        });

        this.$dialog = dialog;
        dialog.show();
    }

    this.$showMark = function() {
        var markId = "alModalDialogMark";
        var markPane = $("#"+ markId);

        if (markPane.length == 0) {
            markPane = $("<div id='" + markId + "'></div>").hide().remove().appendTo("body");
        } else if (markPane.length > 1) {
            markPane = markPane.eq(0);
        }

        markPane.css({
            "z-index": this.$options.mark.zIndex,
            "position": "absolute",
            "top": "0",
            "left": "0",
            "background": this.$options.mark.background,
            "filter": "Alpha(opacity=" + (100 - this.$options.mark.alpha) + ")"
        }).width(this.getDocumentWidth()).height(this.getDocumentHeight());

        // embeded function can cannot access this, so
        // assign this to a temprary variable for accessing
        var dialog = this;
        if (this.$options.mark.clickToClose) {
            markPane.click(function() {
                dialog.close();
            });
        }

        this.$mark = markPane;
        markPane.show();
    }

    this.close = function(func) {
        if (typeof(this.$closing) == "function") {
            var r = this.$closing();
            if (typeof(r) == "boolean" && !r) {
                return this;
            }
        }

        if (typeof(this.$dialog) == "object" && this.$dialog != null) {
            this.$dialog.hide();
        }

        this.$removeMark();

        if (typeof(this.$closed) == "function") {
            this.$closed();
        }

        this.distruct();
    }

    this.$removeMark = function() {
        if (typeof(this.$mark) == "object" && this.$mark != null) {
            this.$mark.hide();
            this.$mark.remove();
        }
    }

    this.getDocumentWidth = function() {
        return this.$getDocumentSide("width");
    }

    this.getDocumentHeight = function() {
        return this.$getDocumentSide("height");
    }

    this.$getDocumentSide = function(side) {
        if (typeof(side) != "string" || !side.match(/width|height/i)) {
            return 0;
        }
        var side = side.toLowerCase();
        var Side = side.replace(/^./, function(c) {return c.toUpperCase();});

        if ($.browser.msie && $.browser.version < 7) {
            var scrollSide = Math.max(
                eval("document.documentElement.scroll" + Side),
                eval("document.body.scroll" + Side)
            );
            var offsetSide = Math.max(
                eval("document.documentElement.offset" + Side),
                eval("document.body.offset" + Side)
            );

            if (scrollSide < offsetSide) {
                return "" + eval("$(window)." + side + "()") + "px"
            } else {
                return "" + scrollSide + "px";
            }
        } else {
            return "" + eval("$(document)." + side + "()") + "px";
        }
    }

    this.distruct = function() {
        for (var i = 0; i < this.domsWithRef.length; i++) {
            this.domsWithRef[i].alDialog = null;
        }
        this.domsWithRef.splice(0, this.domsWithRef.length);
    }

    // construct
    this.$init(selector, options);
}
